<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 发布订阅模式中有三个对象，发布者、订阅者和调度中心，下面的PubSub其实是实现的调度中心
        // 三者的关系是：首先订阅者在调度中心上订阅某个事件，说白了就是在某个事件触发时去执行某个函数，具体函数体内容是啥，跟订阅者已经没啥关系了，只是说这个在调度中心上添加<事件--回调>键值对的是订阅者
        // 发布者去触发某个事件，也就是让调度中心的事件对应的回调全部执行
        // 我们要写的调度中心其实就是一个<事件--回调>记录中心，提供subscribe（订阅）方法，也就是添加<事件--回调>记录;publish方法作用就是触发<事件>对应的所有回调；当然还有unSubscribe以及once（subscribe时增强回调函数即可，也就是增加unsubscribe的逻辑）
        class PubSub {
            constructor() {
                this.message = new Map();
            }
            subscribe(type, cb) {
                if(this.message.has(type)) {
                    this.message.set(type, [...this.message.get(type), cb]);
                }else {
                    this.message.set(type, [cb]);
                }
            }
            publish(type, data) {

                if(!this.message.has(type)) return;

                this.message.get(type).forEach((item)=>item(data));
            }
            unsubscribe(type, cb) {
                if(!this.message.has(type)) {
                    return;
                }
                if(!cb) {
                    this.message.delete(type);
                }else {
                    this.message.set(type, this.message.get(type).filter(item => item !== cb))
                }
            }
            // 只执行一次订阅的事件，然后将订阅移除
            once(type, cb) {
                const fn = (data) => {
                    cb(data);
                    this.unsubscribe(type, fn);
                };
                this.subscribe(type, fn);
            }
        }
        let pubsub = new PubSub();
        let fn1 = function(data) {
            console.log("fn1", data);
        }
        let fn2 = function(data) {
            console.log("fn2", data);
        }
        pubsub.subscribe("事件1", fn1);
        pubsub.subscribe("事件1", fn2);
        /*
            pubsub.publish("事件1", 1111);
            output:
                fn1 1111
                fn2 1111
        */
        
        /*
            pubsub.unsubscribe("事件1", fn1);
            pubsub.publish("事件1", 12312);
            output:
                fn2 12312
        */
    </script>
</body>
</html>